﻿#include "EditorTextFilePageViewModel.h"

#include "Framework/Application.h"
#include "Font/FontSubsystem.h"
#include "Platform/PlatformInterface.h"
#include "Document/TextDocument.h"
#include "Document/PieceTable.h"
#include "Misc/EditorPathUtils.h"
#include "Language/ScriptIntelliSense.h"
#include "Language/EditorScriptFile.h"
#include "Framework/Editor.h"
#include "Theme/EditorTheme.h"

#include "Widgets/Window.h"
#include "Asset/EditorDefaultPackage.h"

#include "Language/EditorScriptDebugSubsystem.h"
#include "Platform/PlatformInterface.h"

void REditorTextFilePageViewModel::BindModel(TSharedObjectPtr<REditorPageModel> InModel)
{
    Super::BindModel(InModel);
    Model = InModel;


    Font=RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    LineHeight=Font->GetLineHeight(FontSize);

    if(WHE::IsScriptFile(Model->GetFilePath()))
    {
        TSharedObjectPtr<RTextDocument> TextDocument=Model->GetDocument();
        auto IntelliSenseSubsystem=REditor::Get()->GetSubsystem<RScriptIntelliSenseSubsystem>();
        auto ScriptFile=IntelliSenseSubsystem->FindOrCreateScriptFile(TextDocument);
        TextRanderer=ScriptFile;

        Icon=REditorDefaultPackage::Get()->GetIcon(U"ScriptFile");
    }

}

TSharedObjectPtr<RTexture2D> REditorTextFilePageViewModel::GetIcon() const
{
    return Icon;
}

CString REditorTextFilePageViewModel::GetTitle() const
{
    return Model->GetFilePath().GetFileOrDirectoryName();
}

float REditorTextFilePageViewModel::GetLineHeight() const
{
    return LineHeight;
}

float REditorTextFilePageViewModel::GetLineNumberTextWidth() const
{
    return  60.0f;
}

SColor REditorTextFilePageViewModel::GetLineNumberTextColor(int64_t InVisibleLineIndex) const
{
    static SColor LineNumberColor=SColor::FromHexRGB(0x6E7681);
    return LineNumberColor;
}

int64_t REditorTextFilePageViewModel::GetDocumentLineCount() const
{
    return Model->GetDocument()->GetPieceTable().GetLineCount();
}

int64_t REditorTextFilePageViewModel::GetLineIndex(int64_t InVisibleLineIndex) const
{
    //TODO enable code folding
    return InVisibleLineIndex;
}

CString REditorTextFilePageViewModel::GetTextOfRange(
    int64_t InStartVisibleLineIndex,
    int64_t InEndVisibleLineIndex,
    int64_t &OutStartCharIndex,
    int64_t & OutEndCharIndex
    ) const
{
    return Model->GetDocument()->GetPieceTable().GetTextOfRange(
        GetLineIndex(InStartVisibleLineIndex),
        GetLineIndex(InEndVisibleLineIndex),
        OutStartCharIndex,
        OutEndCharIndex
        );
}

TVector<SColorfulTextColor> REditorTextFilePageViewModel::GetTextColorsOfRange(int64_t InStartCharIndex, int64_t InEndCharIndex) const
{
    auto& Colors=TextRanderer->GetColors();

    TVector<SColorfulTextColor> Result;

    for(int64_t i=Colors.Num()-1;i>=0;--i)
    {

        if(Colors[i].StartIndex>InEndCharIndex)
        {
            continue;
        }

        Result.Add(Colors[i]);
        Result.Last().StartIndex-=InStartCharIndex;

        if(Result.Last().StartIndex<=0)
        {
            Result.Last().StartIndex=0;
            break;
        }
    }
    Result.Reverse();


    return Result;

}

CString REditorTextFilePageViewModel::GetLineContent(int64_t InVisibleLineIndex) const
{
    return Model->GetDocument()->GetPieceTable().GetLineText(GetLineIndex(InVisibleLineIndex));
}


const TVector<SColorfulTextColor> &REditorTextFilePageViewModel::GetTextColors() const 
{
    return TextRanderer->GetColors();
}

CString REditorTextFilePageViewModel::GetWholeText() const
{
    return Model->GetDocument()->GetPieceTable().GetText();
}

float REditorTextFilePageViewModel::GetContentAreaYOffset() const
{
    return Model->ContentAreaYOffset;
}

REditorTextFilePageViewModel::SVerticleScrollBarPositionAndHeight REditorTextFilePageViewModel::GetVerticalScrollbarPositionAndHeight(float VisibleAreaHeight) const
{
    int64_t TotalLineCount=GetDocumentLineCount();
    float PositionPercent=GetContentAreaYOffset()/((TotalLineCount-1)* GetLineHeight());
    float HeightPercent=VisibleAreaHeight/((TotalLineCount-1)* GetLineHeight()+VisibleAreaHeight);

    SVerticleScrollBarPositionAndHeight Result;
    Result.Height=HeightPercent * VisibleAreaHeight;
    Result.Position=PositionPercent * (VisibleAreaHeight-Result.Height);
    return Result;
}

void REditorTextFilePageViewModel::UpdateVerticalScrollbarPercent(float InVisibleAreaHeight, float RelativeMouseY)
{
    int64_t TotalLineCount=GetDocumentLineCount();
    float HeightPercent=InVisibleAreaHeight/((TotalLineCount-1)* GetLineHeight()+InVisibleAreaHeight);
    if(HeightPercent==1)
    {
        //bar height== 0
        Model->ContentAreaYOffset=0;
        return;
    }
    
    float VerticalScrollbarHeight=HeightPercent * InVisibleAreaHeight;
    float VerticalScrollbarPosition=RelativeMouseY-VerticalScrollbarHeight/2;
    VerticalScrollbarPosition=CMathBase::Clamp(VerticalScrollbarPosition,0.0f,InVisibleAreaHeight-VerticalScrollbarHeight);
    float PositionPercent=VerticalScrollbarPosition/(InVisibleAreaHeight-VerticalScrollbarHeight);
    Model->ContentAreaYOffset=PositionPercent*((TotalLineCount-1)* GetLineHeight());
}

SColor REditorTextFilePageViewModel::GetDisabledDebugPointColor()
{
    return REditor::Get()->CurrentTheme->DisabledDebugPointColor;
}

SColor REditorTextFilePageViewModel::GetBreakpointColor()
{
    return REditor::Get()->CurrentTheme->BreakpointColor;
}

SColor REditorTextFilePageViewModel::GetAddingBreakpointColor()
{
    return REditor::Get()->CurrentTheme->AddingBreakpointColor;
}

REditorTextFilePageViewModel::EDebugPointType REditorTextFilePageViewModel::GetDebugPointType(int64_t InVisibleLineIndex) const
{
    auto BreakpointSubsystem=REditor::Get()->GetSubsystem<REditorScriptDebugSubsystem>();
    auto Type=BreakpointSubsystem->GetBreakpointType(Model->GetFileID(),GetLineIndex(InVisibleLineIndex));

    if(Type.HasValue())
    {
        bool Enabled=Type.GetValue();
        if(Enabled)
        {
            return EDebugPointType::Normal;
        }
        else
        {
            return EDebugPointType::Disabled;
        }
    }
    

    if(HoveringVisibleLineIndex==InVisibleLineIndex)
    {
        return EDebugPointType::Adding;
    }

    return EDebugPointType::None;
}

void REditorTextFilePageViewModel::HovorLineNumber(SVec2 RelativeMouseArea)
{
    HoveringVisibleLineIndex=(RelativeMouseArea.Y+Model->ContentAreaYOffset)  /GetLineHeight();
    if(HoveringVisibleLineIndex>=GetDocumentLineCount())
    {
        HoveringVisibleLineIndex=-1;
        return;
    }
}

void REditorTextFilePageViewModel::ClearHoverLineNumber()
{
    HoveringVisibleLineIndex=-1;
}

void REditorTextFilePageViewModel::AddOrRemoveBreakpoint(SVec2 RelativeMouseArea)
{
    int64_t VisibleLineIndex=(RelativeMouseArea.Y+Model->ContentAreaYOffset)  /GetLineHeight();
    if(VisibleLineIndex>=GetDocumentLineCount())
    {
        //out of range, do nothing
        return;
    }

    int64_t LineIndex=GetLineIndex(VisibleLineIndex);
    auto BreakpointSubsystem=REditor::Get()->GetSubsystem<REditorScriptDebugSubsystem>();
    BreakpointSubsystem->AddOrRemoveBreakpoint(Model->GetFileID(),LineIndex);
}

CString REditorTextFilePageViewModel::GetSelectedText() const
{
    if(!HasSelection())
    {
        return U"";
    }

    int64_t StartLineIndex,EndLineIndex,StartColumnIndex,EndColumnIndex;    
    //如果选中区域的开始位置在结束位置之后，则交换两个位置
    if(SelectionStart>SelectionEnd)
    {
        return Model->GetDocument()->GetPieceTable().GetTextIn(
            SelectionEnd,SelectionStart);
    }
    else
    {
        return Model->GetDocument()->GetPieceTable().GetTextIn(
            SelectionStart,SelectionEnd);
    }

}

bool REditorTextFilePageViewModel::Cut()
{
    if(!HasSelection())
    {
        return false;
    }

    CString SelectedText=GetSelectedText();
    IPlatformInterface::GetPlatformInterface()->SetClipboardText(SelectedText);
    
    //设置光标位置
    //如果选中区域的开始位置在结束位置之后，则交换两个位置
    if(SelectionStart>SelectionEnd)
    {
        Model->CursorPosition=SelectionEnd;
    }
    else
    {
        Model->CursorPosition=SelectionStart;
    }

    //删除选中的文本
    Model->GetDocument()->GetPieceTable().DeleteAfterCusor(
        SelectedText.GetLength()
        ,Model->CursorPosition
        );
    
    //清空选中区域
    SelectionStart=SelectionEnd;
    
    PostUserChangedText();

    return true;
}

bool REditorTextFilePageViewModel::Copy()
{
    if(!HasSelection())
    {
        return false;
    }

    IPlatformInterface::GetPlatformInterface()->SetClipboardText(GetSelectedText());
    return true;
}

bool REditorTextFilePageViewModel::Paste()
{
    if(!ShouldShowCursor())
    {
        return false;
    }

    CString InsertString=IPlatformInterface::GetPlatformInterface()->GetClipboardText();
    if(InsertString.IsEmpty())
    {
        return false;
    }
    Model->GetDocument()->GetPieceTable().InsertTextAtCursor(
        InsertString
        ,Model->CursorPosition
        );

    PostUserChangedText();

    return true;
}

bool REditorTextFilePageViewModel::CanCut() const
{
    return HasSelection();
}

bool REditorTextFilePageViewModel::CanCopy() const
{
    return HasSelection();
}

bool REditorTextFilePageViewModel::CanPaste() const
{
    return IPlatformInterface::GetPlatformInterface()->HasClipboardText();
}

void REditorTextFilePageViewModel::PostUndo()
{
    PostUserChangedText();
}

void REditorTextFilePageViewModel::PostRedo()
{
    PostUserChangedText();
}

TVector<REditorTextFilePageViewModel::SHighlightRange> REditorTextFilePageViewModel::GetHighlightRanges() const
{
    TVector<REditorTextFilePageViewModel::SHighlightRange> Result;   
    CreateSelectionHighlightRange(Result);

    //高亮搜索结果
    for(int64_t SearchResultIndex=0;SearchResultIndex<SearchResults.Num();++SearchResultIndex)
    {
        auto& SearchResult=SearchResults[SearchResultIndex];
        if(SearchResult.Start.LineIndex>MaxVisibleLine
            || SearchResult.End.LineIndex<MinVisibleLine
        )
        {
            continue;
        }

        static SColor Color=SColor::FromHexRGB(0x623315);
        //当前光标所在的搜索结果
        static SColor CurrentColor=SColor::FromHexRGB(0x9E6A03);

        auto& HighlightRange= Result.Emplace();
        HighlightRange.StartLineIndex=SearchResult.Start.LineIndex;
        HighlightRange.EndLineIndex=SearchResult.End.LineIndex;
        HighlightRange.StartColumnIndex=SearchResult.Start.ColumnIndex;
        HighlightRange.EndColumnIndex=SearchResult.End.ColumnIndex;
        HighlightRange.Color= 
            CurrentSearchIndex==SearchResultIndex?
            CurrentColor:Color;
    }
   

    return Result;
}

void REditorTextFilePageViewModel::CreateSelectionHighlightRange(TVector<SHighlightRange> &InOutHighlightRanges) const
{
    
    if(!HasSelection())
    {
        return;
    }

    //高亮选中区域
    {
        
        auto& SelectedRnage= InOutHighlightRanges.Emplace();
        SelectedRnage.Color=SColor::FromHexRGB(0x264F78);
        
        //如果选中区域的开始位置在结束位置之后，则交换两个位置
        if(SelectionStart>SelectionEnd)
        {
            SelectedRnage.StartLineIndex=SelectionEnd.LineIndex;
            SelectedRnage.EndLineIndex=SelectionStart.LineIndex;
            SelectedRnage.StartColumnIndex=SelectionEnd.ColumnIndex;
            SelectedRnage.EndColumnIndex=SelectionStart.ColumnIndex;
        }
        else
        {
            SelectedRnage.StartLineIndex=SelectionStart.LineIndex;
            SelectedRnage.EndLineIndex=SelectionEnd.LineIndex;
            SelectedRnage.StartColumnIndex=SelectionStart.ColumnIndex;
            SelectedRnage.EndColumnIndex=SelectionEnd.ColumnIndex;
        }

    }

    //高亮与选中文本相同的文字
    if(SelectionStart.LineIndex!=SelectionEnd.LineIndex)
    {
        //如果是多行文本则不考虑
        return ;
    }

    
    CString SelectedText=GetSelectedText();

    //逐行查找相同的文本
    for(int32_t Line=MinVisibleLine;Line<=MaxVisibleLine; Line++)
    {
        CString LineContent=GetLineContent(Line);
        int32_t StartIndex=0;
        while(true)
        {
            int32_t Index=LineContent.Find(SelectedText,StartIndex);
            if(Index==-1)
            {
                break;
            }

            if(Line==SelectionStart.LineIndex
                &&(Index==SelectionStart.ColumnIndex || Index==SelectionEnd.ColumnIndex)
            )
            {
                //如果是选中的文本，则跳过
                StartIndex=Index+SelectedText.GetLength();
                continue;
            }
            

            auto& HighlightRange= InOutHighlightRanges.Emplace();
            HighlightRange.Color=SColor(1,1,1,0.1);
            HighlightRange.StartLineIndex=Line;
            HighlightRange.EndLineIndex=Line;
            HighlightRange.StartColumnIndex=Index;
            HighlightRange.EndColumnIndex=Index+SelectedText.GetLength();

            StartIndex=Index+SelectedText.GetLength();
        }
    }
    

}

void REditorTextFilePageViewModel::UpdateVisibleLineRange(const SVec2 &InVisibleAreaSize)
{
    //range of visible area ,in document space
    float MinVisibleContentY=GetContentAreaYOffset();
    float MaxVisibleContentY=MinVisibleContentY+ InVisibleAreaSize.Y;
    
    MinVisibleLine=MinVisibleContentY/LineHeight;
    MaxVisibleLine=MaxVisibleContentY/LineHeight;

    int64_t VisibleLineCount=GetDocumentLineCount();
    if(VisibleLineCount<MaxVisibleLine)
    {
        MaxVisibleLine=VisibleLineCount-1;
    }    
}

void REditorTextFilePageViewModel::ScrollTo(const SDocumentPosition &InPosition)
{
    //暂不考虑水平滚动，因为还没有实现水平滚动


    if(InPosition.LineIndex>=MaxVisibleLine
        ||InPosition.LineIndex<=MinVisibleLine
    )
    {
        int64_t HalfVisibleLineCount=(MaxVisibleLine-MinVisibleLine)/2;
        int64_t TargetFistLine= InPosition.LineIndex-HalfVisibleLineCount;
        if(TargetFistLine<0)
        {
            TargetFistLine=0;
        }

        Model->ContentAreaYOffset=TargetFistLine*LineHeight;
    }
    else
    {
        //目标位置就在可视区域内，不需要滚动
    }
}

void REditorTextFilePageViewModel::SearchText(const CString &InSearchText)
{
    TextForSearch=InSearchText;
    SearchResults=SearchTextImplement(InSearchText);
    UpdateSearchIndex();
}

void REditorTextFilePageViewModel::ClearSearch()
{
    SearchResults.Clear();
    TextForSearch.Clear();
}

int64_t REditorTextFilePageViewModel::GetSearchResultCount() const
{
    return SearchResults.Num();
}

int64_t REditorTextFilePageViewModel::GetCurrentSearchIndex() const
{
    return CurrentSearchIndex;
}

void REditorTextFilePageViewModel::GotoNextMatched()
{
    if(CurrentSearchIndex<(int64_t)SearchResults.Num()-1)
    {
        CurrentSearchIndex++;

        ScrollTo(SearchResults[CurrentSearchIndex].Start);
        Model->CursorPosition=SearchResults[CurrentSearchIndex].End;
    }
}

void REditorTextFilePageViewModel::GotoPreviousMatched()
{
    if(CurrentSearchIndex>0)
    {
        CurrentSearchIndex--;

        ScrollTo(SearchResults[CurrentSearchIndex].Start);
        Model->CursorPosition=SearchResults[CurrentSearchIndex].End;
    }
}

TVector<REditorTextFilePageViewModel::SearchResult> REditorTextFilePageViewModel::SearchTextImplement(const CString &InSearchText) const
{
    TVector<SearchResult> Result;
    if(InSearchText.IsEmpty())
    {
        return Result;
    }

    //将文本分割成多行
    TVector<CString> SearchLines= InSearchText.Split(U'\n');

    int64_t LineCount=GetDocumentLineCount();
    for(int64_t LineIndex=0;LineIndex<LineCount;++LineIndex)
    {
        CString LineContent=GetLineContent(LineIndex);
        int64_t ColumnIndex=0;
        while(true)
        {
            int64_t Index=LineContent.Find(SearchLines[0],ColumnIndex);
            if(Index==-1)
            {
                break;
            }

            auto StartPosition=SDocumentPosition(LineIndex,Index);

            //检查剩余行是否匹配
            bool bMatch=true;
            for(int32_t SearchTextLine=1; SearchTextLine<SearchLines.Num();SearchTextLine++)
            {
                CString NextLineContent=GetLineContent(LineIndex+SearchTextLine);
                if(SearchTextLine==SearchLines.Num()-1)
                {
                    //这是最后一行，可以不完全相等
                    int64_t Index=LineContent.Find(SearchLines[SearchTextLine],0);
                    if(Index!=0)
                    {
                        //最后一行匹配不成功
                        bMatch=false;
                    }
                }
                else
                {
                    if(NextLineContent==SearchLines[SearchTextLine])
                    {
                        //匹配成功,继续匹配下一行
                    }
                    else
                    {
                        //匹配不成功
                        bMatch=false;
                        break;
                    }
                }
            }

            if(bMatch)
            {

                auto& Matched=Result.Emplace();
                Matched.Start=StartPosition;

                if(SearchLines.Num()>1)
                {
                    Matched.InclusiveEnd.LineIndex=LineIndex+SearchLines.Num()-1;
                    Matched.InclusiveEnd.ColumnIndex=SearchLines.Last().GetLength()-1;
                }
                else
                {
                    Matched.InclusiveEnd.LineIndex=LineIndex;
                    Matched.InclusiveEnd.ColumnIndex= Index+InSearchText.GetLength()-1;
                }

                if(SearchLines.Num()>1)
                {
                    LineIndex+= SearchLines.Num()-1;
                    ColumnIndex=SearchLines.Last().GetLength();
                }
                else
                {
                    ColumnIndex=Index+InSearchText.GetLength();
                }
                Matched.End=SDocumentPosition(LineIndex,ColumnIndex);
            }
        }
    }

    return Result;
}

void REditorTextFilePageViewModel::UpdateSearchIndex()
{
    //如果光标出现在搜索结果文本的开头或者结尾则视为当前正在查看该搜索结果

    for(int64_t SearchIndex=0;SearchIndex<SearchResults.Num(); SearchIndex++)
    {
        if(Model->CursorPosition>=SearchResults[SearchIndex].Start
            && Model->CursorPosition< SearchResults[SearchIndex].End
        )
        {
            CurrentSearchIndex=SearchIndex;
            return;
        }

        if(SearchResults[SearchIndex].Start> Model->CursorPosition)
        {
            //显然已经不可能找到了了
            break;
        }
    
    }

    CurrentSearchIndex=-1;
    return;
}

void REditorTextFilePageViewModel::Replace(const CString &InNewText)
{
    if(CurrentSearchIndex==-1)
    {
        return;
    }

    //将当前文本替换为新文本
    Model->GetDocument()->GetPieceTable().ReplaceTextAndUpdateCursor(
        TextForSearch
        ,InNewText
        ,SearchResults[CurrentSearchIndex].Start
        ,SearchResults[CurrentSearchIndex].InclusiveEnd
        ,Model->CursorPosition 
    );

    //更新搜索结果
    SearchResults=SearchTextImplement(TextForSearch);
    if(CurrentSearchIndex< SearchResults.Num())
    {
        //不做修改
    }
    else
    {
        UpdateSearchIndex();
    }


}

void REditorTextFilePageViewModel::ReplaceAll(const CString &InNewText)
{
    if(SearchResults.Num()==0)
    {
        return;
    }

    //将所有文本替换为新文本

    TVector<SDocumentPosition> StartPositions;
    TVector<SDocumentPosition> EndPositions;
    for(int64_t i=0; i<SearchResults.Num();++i)
    {
        StartPositions.Add(SearchResults[i].Start);
        EndPositions.Add(SearchResults[i].InclusiveEnd);
    }

    Model->GetDocument()->GetPieceTable().ReplaceTextBatchAndUpdateCursor(
        TextForSearch
        ,InNewText
        ,StartPositions
        ,EndPositions
        ,Model->CursorPosition 
    );
   
    //更新搜索结果
    SearchResults.Clear();
    CurrentSearchIndex=-1;
}

void REditorTextFilePageViewModel::PostUserChangedText()
{
    //更新搜索结果
    SearchResults=SearchTextImplement(TextForSearch);
    UpdateSearchIndex();
}

void REditorTextFilePageViewModel::Tick(float DeltaSeconds)
{
    if(!Model
       ||!Model->bIsCursorVisible)
    {
        return;
    }

    ElapsedTime+=DeltaSeconds;

    if(ElapsedTime> CursorBlinkInterval)
    {
        ElapsedTime-=CursorBlinkInterval;
        CursorShowState=!CursorShowState;
    }

}

bool REditorTextFilePageViewModel::ShouldShowCursor() const
{
    return Model->bIsCursorVisible && CursorShowState;
}

void REditorTextFilePageViewModel::StartEdit(RWidgetWeakPtr InContentAreaWidget)
{
    Model->bIsCursorVisible=true;
    CursorShowState = true;
    ElapsedTime = 0.0f;

    IPlatformInterface::GetPlatformInterface()->StartTextInput(
        InContentAreaWidget->GetWindow()->GetWindowID()
        ,
            InContentAreaWidget->GetWindow()->ContentSpaceToWindowSpace(
            SIntPoint(
                InContentAreaWidget->PresentAbsPosition.X 
                ,InContentAreaWidget->PresentAbsPosition.Y+InContentAreaWidget->GetPresentSize().Y)
        )
    );

}

void REditorTextFilePageViewModel::EndEdit()
{
    Model->bIsCursorVisible=false;

    IPlatformInterface::GetPlatformInterface()->StopTextInput();
}

int64_t REditorTextFilePageViewModel::GetCursorLineIndex() const
{
    return Model->CursorPosition.LineIndex;
}

int64_t REditorTextFilePageViewModel::GetCursorColumnIndex() const
{
    return Model->CursorPosition.ColumnIndex;
}

void REditorTextFilePageViewModel::SetCursorLineIndex(int64_t InLineIndex)
{
    Model->CursorPosition.LineIndex=InLineIndex;
}

void REditorTextFilePageViewModel::SetCursorColumnIndex(int64_t InColumnIndex)
{
    Model->CursorPosition.ColumnIndex=InColumnIndex;
}

bool REditorTextFilePageViewModel::OnTextInput(const STextInputEvent &InEvent)
{
    IsVerticalMoveCursor=false;

    Model->GetDocument()->GetPieceTable().InsertTextAtCursor(
        InEvent.GetInputText()
        ,Model->CursorPosition
        );

    PostUserChangedText();

    CursorShowState = true;
    ElapsedTime = 0.0f;
    return true;

}

bool REditorTextFilePageViewModel::OnKeyboardEvent(const SKeyboardEvent & InKeyboardEvent)
{
    if(InKeyboardEvent.KeyState!=EKeyState::Pressed)
    {
        return false;
    }

    auto Key=InKeyboardEvent.Key;

    if(Key!= EKey::Down && Key!= EKey::Up)
    {
        IsVerticalMoveCursor=false;
    }

    switch (Key)
    {
        case EKey::Down:
        {
            if(!IsVerticalMoveCursor)
            {
                IsVerticalMoveCursor=true;
                CursorColumnBeforeVerticalMove=
                   GetCursorColumnIndex();
            }
            Model->GetDocument()->GetPieceTable().MoveCursorDown(
                CursorColumnBeforeVerticalMove
                ,Model->CursorPosition
                );
            break;
        }

        case EKey::Up:
        {
            if(!IsVerticalMoveCursor)
            {
                IsVerticalMoveCursor=true;
                CursorColumnBeforeVerticalMove=
                    GetCursorColumnIndex();
            }
            Model->GetDocument()->GetPieceTable().MoveCursorUp(
                CursorColumnBeforeVerticalMove
                ,Model->CursorPosition
                );
            break;
        }

        case EKey::Left:
        {
            Model->GetDocument()->GetPieceTable().MoveCursorLeft(Model->CursorPosition);
            break;
        }

        case EKey::Right:
        {
            Model->GetDocument()->GetPieceTable().MoveCursorRight(Model->CursorPosition);
            break;
        }

        case EKey::Enter:
        {
            //insert a '\n' and some spaces
            int64_t LineIndex=GetCursorLineIndex();
            CString LineContent=GetLineContent(LineIndex);

            CString InsertString=U"\n";
            for(int64_t i=0;i<LineContent.GetLength();++i)
            {
                if(LineContent[i]==U' ')
                {
                    InsertString+=U' ';
                }
                else
                {
                    break;
                }
            }

            Model->GetDocument()->GetPieceTable().InsertTextAtCursor(
                InsertString
                ,Model->CursorPosition
                );

            PostUserChangedText();
            break;
        }

        case EKey::Backspace:
        {
            Model->GetDocument()->GetPieceTable().BackspaceAtCursor(Model->CursorPosition);
            
            PostUserChangedText();
            break;
        }

        case EKey::Tab:
        {
            //replace tab with 4 spaces
            int64_t LineIndex=GetCursorLineIndex();
            CString LineContent=GetLineContent(LineIndex);
            int64_t Column=GetCursorColumnIndex();

            //中文字符占两个空格
            //由于column的最大值就是LineContent的长度，所以这里不需要考虑越界问题
            int64_t CursorColumnOnScreen=0;
            for(int64_t i=0;i<Column;++i)
            {
                char32_t& Char=LineContent[i];
                if(Char<0x80)
                {
                    CursorColumnOnScreen+=1;
                }
                else
                {
                    //simple solution, just treat all non-ascii characters as 2 spaces
                    //TODO handle non-ascii characters correctly
                    CursorColumnOnScreen+=2;
                }
            }

            int64_t SpaceCount=4-CursorColumnOnScreen%4;

            CString SpaceString;
            switch (SpaceCount)
            {
                case 1:
                {
                    SpaceString=U" ";
                    break;
                }

                case 2:
                {
                    SpaceString=U"  ";
                    break;
                }

                case 3:
                {
                    SpaceString=U"   ";
                    break;
                }

                case 4:
                {
                    SpaceString=U"    ";
                    break;
                }
            }

            Model->GetDocument()->GetPieceTable().InsertTextAtCursor(
                SpaceString,Model->CursorPosition);

            PostUserChangedText();
            break;
        }
    }

    CursorShowState = true;
    ElapsedTime = 0.0f;
    return true;
}

SDocumentPosition REditorTextFilePageViewModel::CalculateCursorPosition(SVec2 RelativeMouseArea)
{
    float LineHeight = GetLineHeight();
    int64_t LineIndex=(RelativeMouseArea.Y+Model->ContentAreaYOffset) /LineHeight;
    int64_t ColumnIndex=0;
    CString LineContent=GetLineContent(LineIndex);
    if(LineContent.EndsWith(U'\n'))
    {
        LineContent=LineContent.SubString(0,LineContent.GetLength()-1);
    }


    ColumnIndex=RFontApplicationSubsystem::GetInstance()->CalculateCursorIndex(
        LineContent
        ,Font
        ,FontSize
        ,RelativeMouseArea.X
        );


    return SDocumentPosition(LineIndex,ColumnIndex);
            
}
